package com.fd;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.FastDateFormat;

import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * mysql慢查询日志解析器
 *
 * @author YangXiaoLong
 * @since 1.0.0
 */
public class SlowLogParser {
    // 正则表达式来匹配信息
    private static final String TIME_PATTERN = "# Time: (.+)";
    private static final String USER_HOST_PATTERN = "# User@Host: (.+?)\\[(.+?)\\] @  \\[(.+?)\\]  Id: (.+)";
    private static final String QUERY_TIME_PATTERN = "# Query_time: (.+)  Lock_time: (.+) Rows_sent: (.+)  Rows_examined: (.+)";
    private static final String QUERY_PATTERN = "(select[\\s\\S]*?;)";

    private static SlowLogProperties SLOW_LOG_PROPERTIES;

    public static void main(String[] args) throws SQLException {
        initConfig();
        //读取日志文件内容
        String logContent = loadSlowLogContent();
        //解析慢查询日志文件
        List<SlowQueryLog> slowQueryLogs = parseSlowLog(logContent);
        //写入数据库
        writeToDatabase(slowQueryLogs);
        releaseResource();
    }

    /**
     * 初始化系统配置
     *
     * @author YangXiaoLong
     * @since 1.0.0
     */
    private static void initConfig() {
        loadProperties();
        //初始化数据库配置
        DatabaseConnection.initConnection(SLOW_LOG_PROPERTIES);
    }

    /**
     * 加载配置文件
     *
     * @author YangXiaoLong
     * @since 1.0.0
     */
    private static void loadProperties() {
        Properties properties = new Properties();
        try (InputStream input = DatabaseOperations.class.getClassLoader().getResourceAsStream("application.properties")) {
            properties.load(input);
            SLOW_LOG_PROPERTIES = SlowLogProperties.getSlowLogProperties(properties);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 写入数据库
     *
     * @param slowQueryLogs 慢速查询日志记录
     * @author YangXiaoLong
     * @since 1.0.0
     */
    private static void writeToDatabase(List<SlowQueryLog> slowQueryLogs) {
        for (SlowQueryLog slowQueryLog : slowQueryLogs) {
            final String insertSQL = slowQueryLog.toInsertSQL();
            DatabaseOperations.insert(insertSQL);
        }
        System.out.println("写入数据成功");
    }

    /**
     * 载入慢速日志内容
     *
     * @return {@link String}
     * @author YangXiaoLong
     * @since 1.0.0
     */
    private static String loadSlowLogContent() {
        try {
            return new String(Files.readAllBytes(Paths.get(SLOW_LOG_PROPERTIES.getLogPath())));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 解析慢日志文件内容
     *
     * @param logContent 文件内容
     * @return {@link List<SlowQueryLog>}
     * @author YangXiaoLong
     * @since 1.0.0
     */
    private static List<SlowQueryLog> parseSlowLog(String logContent) {
        // 提取信息
        List<SlowQueryLog> slowQueryLogs = new ArrayList<>();
        Pattern timePat = Pattern.compile(TIME_PATTERN);
        Pattern userHostPat = Pattern.compile(USER_HOST_PATTERN);
        Pattern queryTimePat = Pattern.compile(QUERY_TIME_PATTERN);
        Pattern queryPat = Pattern.compile(QUERY_PATTERN, Pattern.DOTALL);

        Matcher timeMat = timePat.matcher(logContent);
        Matcher userHostMat = userHostPat.matcher(logContent);
        Matcher queryTimeMat = queryTimePat.matcher(logContent);
        Matcher queryMat = queryPat.matcher(logContent);

        while (timeMat.find()) {
            SlowQueryLog slowQueryLog = new SlowQueryLog();
            String isoTimeString = timeMat.group(1);
            FastDateFormat formatter = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'", TimeZone.getTimeZone("UTC"));
            Date utcDate = DateUtil.parse(isoTimeString, formatter);
            DateTime localDateTime = DateUtil.offsetHour(new DateTime(utcDate), 8);
            slowQueryLog.setQueryTime(DateUtil.format(localDateTime, "yyyy-MM-dd HH:mm:ss"));
            // Match userHost
            if (userHostMat.find(timeMat.end())) {
                String user = userHostMat.group(1) + "[" + userHostMat.group(2) + "]";
                String host = userHostMat.group(3);
                String userId = userHostMat.group(4);
                slowQueryLog.setUser(user);
                slowQueryLog.setHost(host);
                slowQueryLog.setUserId(userId);
            }
            // Match queryTime
            if (queryTimeMat.find(timeMat.end())) {
                Double queryTime = Double.valueOf(queryTimeMat.group(1));
                Double lockTime = Double.valueOf(queryTimeMat.group(2));
                String rowsSent = queryTimeMat.group(3);
                Long rowsExamined = Long.valueOf(queryTimeMat.group(4));
                slowQueryLog.setQueryTimeCost(queryTime);
                slowQueryLog.setLockTime(lockTime);
                slowQueryLog.setRowsSent(Long.valueOf(rowsSent));
                slowQueryLog.setRowsExamined(rowsExamined);
            }
            // Match query
            if (queryMat.find(timeMat.end())) {
                String query = queryMat.group(1).replaceAll("\\s+", " ");
                slowQueryLog.setQuerySql(query);
            }
            slowQueryLogs.add(slowQueryLog);
        }
        return slowQueryLogs;
    }

    /**
     * 释放资源
     *
     * @author YangXiaoLong
     * @since 1.0.0
     */
    private static void releaseResource() throws SQLException {
        DatabaseConnection.getConnection().close();
    }
}
